/**
 * 观察者对象：一个消息容器，三个方法[订阅消息方法、取消订阅的消息方法、发送订阅的消息方法]
 * 订阅者
 * 
 * 消息注册方法
 *      将订阅者注册的消息推入到消息队列中。所需参数：消息类型以及相应的处理动作
 *      在推入到消息队列时如果此消息不存在则应创建一个该消息类型并将该消息放入消息队列中，
 *      如果此消息存在则应该将消息执行方法推入该消息对应的执行方法队列中
 *      这样可以保证多个模块注册同一消息能顺利执行
 * 
 * 发布消息方法
 *      当观察者发布一个消息时，将所有订阅者订阅的消息一次执行。所需参数：消息类型[*]、动作执行时需要传递的参数
 *      在执行消息动作队列之前校验消息的存在是很有必要的。遍历消息执行方法队列，并依次执行
 *      然后将消息类别以及传递的参数打包后依次传入消息执行方法中
 * 
 * 消息注销方法
 *      将订阅者注销的信息从消息队列中清除，所需参数：消息类型，执行的某一动作
 *      为了避免删除消息动作时消息不存在情况的出现，对消息队列中消息的存在性校验也很有必要。
 */
var Observe = (function() {
    // 防止消息队列暴露而将篡改故将消息容器作为静态私有变量保存
    var _messages = {};
    return {
        // 注册信息接口
        regist: function(type, fn) {
            if (typeof _messages[type] === 'undefined') {
                _messages[type] = [fn];
            } else {
                _messages[type].push(fn);
            }
        },
        // 发布信息接口
        fire: function(type, args) {
            if (!_messages[type]) return;
            // 定义消息信息
            var events = {
                type: type,                 //消息类型
                args: args || {}            //消息携带数据
            },
            i = 0,                          //消息动作循环变量
            len = _messages[type].length;   //消息动作长度
            for(; i < len; i++) {
                _messages[type][i].call(this, events);
            }
        },
        // 移除信息接口
        remove: function(type, fn) {
            // 如果消息动作队列存在
            if(_messages[type] instanceof Array) {
                // 从最后一个消息动作遍历
                var i = _messages[type].length - 1;
                for(; i >= 0; i--) {
                    // 如果存在该动作则在消息动作序列中移除相应动作
                    _messages[type][i] === fn && _messages[type].splice(i, 1);
                }
            }
        }
    };
})();

Observe.regist('test', function(e) {
    console.log(e.type, e.args.msg);
});

Observe.fire('test', {msg: '传递参数'});//test 传递参数
 